package com.iretailer.report.analyze.flow;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.iretailer.report.analyze.commonModel.InOutMetric;
import com.iretailer.report.analyze.commonModel.PassengerFlowModel;
import com.iretailer.report.analyze.commonModel.QueueModel;
import com.iretailer.report.analyze.commonModel.ServiceModel;
import com.iretailer.report.analyze.commonUtil.CommonUtil;
import com.iretailer.report.analyze.commonUtil.ResponeResultType;
import com.iretailer.report.influxdb.model.DwellTime;
import com.iretailer.report.influxdb.model.Passengerflow;
import com.iretailer.report.influxdb.model.QueueLength;
import com.iretailer.report.influxdb.service.InfluxdbDwellService;
import com.iretailer.report.influxdb.service.InfluxdbFlowService;
import com.iretailer.report.influxdb.service.InfluxdbQueueService;
import com.iretailer.report.influxdb.util.TableName;
import com.iretailer.report.model.Camera;
import com.iretailer.report.model.CameraZoneCamera;
import com.iretailer.report.model.MallBusinessTime;
import com.iretailer.report.service.BusinessTimeService;
import com.iretailer.report.service.CameraService;
import com.iretailer.report.service.CameraZoneService;
import com.iretailer.report.util.StringUtil;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @Auther: xjw
 * @Date: 2019/3/11 09:59
 * @Description:
 */
@Component
public class FlowInsert {
    private static final Logger log = LoggerFactory.getLogger(FlowInsert.class);

    @Autowired
    private CameraZoneService cameraZoneService;
    @Autowired
    private BusinessTimeService businessTimeService;
    @Autowired
    private InfluxdbFlowService influxdbFlowService;
    @Autowired
    private InfluxdbDwellService influxdbDwellService;
    @Autowired
    private InfluxdbQueueService influxdbQueueService;
    @Autowired
    private CameraService cameraService;

    /**
     * 解析 PassengerFlowModel
     */
    public ResponeResultType analysisCommon(PassengerFlowModel pfm) {
        try {
            Map<String, CameraZoneCamera> cameraZoneMap = cameraZoneService.cameraZonesMap(pfm.getDeviceId());

            if (cameraZoneMap != null && cameraZoneMap.size() > 0) {
                String mallId = null;
                for (CameraZoneCamera czs : cameraZoneMap.values()) {
                    mallId = czs.getMallId();
                    break;
                }
                MallBusinessTime mallBusinessTime = businessTimeService.filterBusinessTime(mallId, LocalDateTime.now());
                ZoneId timezone = ZoneId.systemDefault();
                if (StringUtil.notEmpty(mallBusinessTime.getTimeZone())) {
                    timezone = ZoneId.of(mallBusinessTime.getTimeZone());
                }
                LastDataTime lastDataTime = new LastDataTime();
                boolean flowStatus = flowInsert(lastDataTime, pfm, cameraZoneMap, timezone, mallBusinessTime.getStartTime(), mallBusinessTime.getEndTime());
                boolean serviceStatus = serviceInsert(lastDataTime, pfm, cameraZoneMap, timezone, mallBusinessTime.getStartTime(), mallBusinessTime.getEndTime());
                boolean queueStatus = queueInsert(lastDataTime, pfm, cameraZoneMap, timezone, mallBusinessTime.getStartTime(), mallBusinessTime.getEndTime());
                if (flowStatus && serviceStatus && queueStatus) {
                    ZonedDateTime time = lastDataTime.getLastDataTime();
                    //更新device
                    updateDevice(time, pfm.getDeviceId(), pfm.getMacAddress(), pfm.getIpAddress(), pfm.getSerialNumber());
                    log.info(" device is true |  {} | {}  | {}", pfm.getDeviceId(), pfm.getIpAddress(), JSON.toJSONString(pfm));
                    return ResponeResultType.getOkRequest(pfm.getChannelCloseType());
                }
            } else {
                log.error("device id not find | {} | {} ", pfm.getDeviceId(), JSON.toJSONString(pfm));
                return ResponeResultType.getBadRequest(pfm.getChannelCloseType());
            }

        } catch (Exception e) {
            log.error("flow error | {} | {} ", pfm.getDeviceId(), JSON.toJSONString(pfm));
            log.error(e.getMessage(), e);
            return ResponeResultType.getBadRequest(pfm.getChannelCloseType());
        }
        return ResponeResultType.getBadRequest(pfm.getChannelCloseType());
    }

    /***
     * 客流数据插入
     * @param pfm
     * @param cameraZoneMap
     * @param startTime
     * @param endTime
     * @return
     */
    private boolean flowInsert(LastDataTime lastDataTime, PassengerFlowModel pfm, Map<String, CameraZoneCamera> cameraZoneMap, ZoneId timezone, String startTime, String endTime) {

        List<InOutMetric> inouts = pfm.getInOutMetrics();
        if (inouts != null && inouts.size() > 0) {
            List<Passengerflow> passengerflow = new ArrayList<>();
            List<Passengerflow> passengerflowBusiness = new ArrayList<>();
            for (int i = 0, len = inouts.size(); i < len; i++) {
                InOutMetric inout = inouts.get(i);
                CameraZoneCamera cameraZoneCamera = cameraZoneMap.get(inout.getZone());
                if (cameraZoneCamera != null) {
                    ZonedDateTime time = null;
                    // 用于兼容 irisys
                    if (inout.getZonedDateTime() != null) {
                        time = inout.getZonedDateTime().withZoneSameInstant(timezone);
                    } else {
                        time = ZonedDateTime.of(inout.getDate(), inout.getStartTime(), timezone);
                    }
                    //最后数据时间
                    lastDataTime.setFlowTime(time);
                    Passengerflow args = new Passengerflow();
                    args.setZoneid(cameraZoneCamera.getId().toString());
                    args.setTime(time);
                    args.setCountEnter(inout.getEnter());
                    args.setCountExit(inout.getExit());
                    passengerflow.add(args);

                    //判断是否在营业时间内
                    if (CommonUtil.judgeBusinessTime(time, timezone, startTime, endTime)) {
                        passengerflowBusiness.add(args);
                    }
                } else {
                    log.error("flow zone id not find | {} | {}", pfm.getDeviceId(), JSON.toJSONString(pfm));
                    return false;
                }
            }
            //入历史 库 dwelltime
            if (passengerflow.size() > 0) {
                influxdbFlowService.insertPassengerflow(passengerflow, TableName.Passengerflow.Passengerflow);
            }
            //入营业时间库
            if (passengerflowBusiness.size() > 0) {
                influxdbFlowService.insertPassengerflow(passengerflowBusiness, TableName.Passengerflow.Passengerflow_B);
            }
            log.info(" flow success | {} | {} |size {}", pfm.getDeviceId(), lastDataTime.getFlowTime(), inouts.size());
        } else {
            log.info(" flow success | {} | size is null", pfm.getDeviceId());
        }
        return true;

    }

    /***
     *  Dwelltime 停留
     * @param pfm
     * @param cameraZoneMap
     * @param timezone
     * @param startTime
     * @param endTime
     * @return
     */
    public boolean serviceInsert(LastDataTime lastDataTime, PassengerFlowModel pfm, Map<String, CameraZoneCamera> cameraZoneMap, ZoneId timezone, String startTime, String endTime) {
        List<ServiceModel> services = pfm.getServiceModels();

        if (services != null && services.size() > 0) {
            List<DwellTime> dwelltime = new ArrayList<>();
            List<DwellTime> dwelltimeBusiness = new ArrayList<>();
            for (int i = 0, len = services.size(); i < len; i++) {
                ServiceModel service = services.get(i);
                CameraZoneCamera cameraZoneCamera = cameraZoneMap.get(service.getZone());

                if (cameraZoneCamera != null) {
                    ZonedDateTime time = null;
                    // 用于兼容 irisys
                    if (service.getZonedDateTime() != null) {
                        time = service.getZonedDateTime().withZoneSameInstant(timezone);
                    } else {
                        time = ZonedDateTime.of(service.getDate(), service.getStartTime(), timezone);
                    }
                    lastDataTime.setServicecTime(time);
                    DwellTime args = new DwellTime();
                    args.setZoneid(cameraZoneCamera.getId().toString());
                    args.setTime(time);
                    args.setNumberServed(service.getNumberServed());
                    args.setSecondsOccupied(service.getSecondsOccupied());
                    dwelltime.add(args);

                    if (CommonUtil.judgeBusinessTime(time, timezone, startTime, endTime)) {
                        dwelltimeBusiness.add(args);
                    }
                } else {
                    log.error("service zone id not find | {} | {}", pfm.getDeviceId(), JSON.toJSONString(pfm));
                    return false;
                }

            }
            //入历史 库 dwelltime
            if (dwelltime.size() > 0) {
                influxdbDwellService.insertDwellTime(dwelltime, TableName.Dwell.DwellTime);
            }
            //入营业时间库
            if (dwelltimeBusiness.size() > 0) {
                influxdbDwellService.insertDwellTime(dwelltimeBusiness, TableName.Dwell.DwellTime_B);
            }
            log.info(" serive success | {} | {} | sieze {}", pfm.getDeviceId(), lastDataTime.getServicecTime(), services.size());

        }
        return true;

    }

    /***
     * 队列
     * @param pfm
     * @param cameraZoneMap
     * @param timezone
     * @param startTime
     * @param endTime
     * @return
     */
    private boolean queueInsert(LastDataTime lastDataTime, PassengerFlowModel pfm, Map<String, CameraZoneCamera> cameraZoneMap, ZoneId timezone, String startTime, String endTime) {

        List<QueueModel> queues = pfm.getQueueModels();
        if (queues != null && queues.size() > 0) {
            List<QueueLength> queueLengths = new ArrayList<>();
            List<QueueLength> queueLength_busienss = new ArrayList<>();
            for (int i = 0, len = queues.size(); i < len; i++) {
                QueueModel queue = queues.get(i);
                CameraZoneCamera cameraZoneCamera = cameraZoneMap.get(queue.getZone());
                if (cameraZoneCamera != null) {
                    ZonedDateTime time = null;
                    // 用于兼容 irisys
                    if (queue.getZonedDateTime() != null) {
                        time = queue.getZonedDateTime().withZoneSameInstant(timezone);
                    } else {
                        time = ZonedDateTime.of(queue.getDate(), queue.getStartTime(), timezone);
                    }
                    lastDataTime.setQueueTime(time);
                    QueueLength qu = new QueueLength();
                    qu.setZoneId(cameraZoneCamera.getId().toString());
                    qu.setTime(time);
                    qu.setAvgLength(queue.getAvgLen());
                    qu.setMaxLength(queue.getMaxLen());
                    queueLengths.add(qu);
                    //判断是否在营业时间内
                    if (CommonUtil.judgeBusinessTime(time, timezone, startTime, endTime)) {
                        queueLength_busienss.add(qu);
                    }
                } else {
                    log.error("queue zone id not find | {} | {}", pfm.getDeviceId(), JSON.toJSONString(pfm));
                    return false;
                }

            }

            //入历史库
            if (queueLengths.size() > 0) {
                influxdbQueueService.insertQueueLength(queueLengths, TableName.Queue.QueueLength);
            }
            //入营业时间库
            if (queueLength_busienss.size() > 0) {
                influxdbQueueService.insertQueueLength(queueLength_busienss, TableName.Queue.QueueLength);
            }
            log.info(" queue success | {} | {} | sieze {}", pfm.getDeviceId(), lastDataTime.getQueueTime(), queues.size());
        }
        return true;
    }


    /**
     * 更新设备的信息
     */
    public void updateDevice(ZonedDateTime lastDataTime, String deviceId, String macAddr, String ipAddr,  String serialNumber) {

        Camera camera = cameraService.selectByDeviceId(deviceId);
        long m = Duration.between(LocalDateTime.now(), camera.getUpdateTime()).toMinutes();
        if (m >= 5 || m < 0) {
//            if (StringUtils.isNotEmpty(deviceType)) {
//                camera.setDeviceType(deviceType);
//            }
            if (StringUtils.isNotEmpty(serialNumber)) {
                camera.setSerialNumber(serialNumber);
            }

            if (StringUtils.isNotEmpty(macAddr)) {
                camera.setMacAddress(macAddr);
            } else if (!StringUtils.isNotEmpty(camera.getMacAddress())) {
                camera.setMacAddress(" ");
            }
            if (StringUtils.isNotEmpty(ipAddr)) {
                camera.setIpAddress(ipAddr);
            } else if (!StringUtils.isNotEmpty(camera.getIpAddress())) {
                camera.setIpAddress("");
            }
            camera.setUpdateTime(LocalDateTime.now());
            if (lastDataTime != null) {
                camera.setLastDataTime(lastDataTime.toLocalDateTime());
            }
            cameraService.analysisUpdateCamera(camera);
            log.debug("{} update {}", LocalDateTime.now(), deviceId);
        } else {
            log.debug("{} not update {}", LocalDateTime.now(), deviceId);
        }
    }




    @Data
    public static class LastDataTime {
        private ZonedDateTime flowTime;
        private ZonedDateTime servicecTime;
        private ZonedDateTime queueTime;

        public ZonedDateTime getLastDataTime() {
            ZonedDateTime lastDateTime = flowTime;
            if (servicecTime != null) {
                if (lastDateTime == null || servicecTime.isAfter(lastDateTime)) {
                    lastDateTime = servicecTime;
                }
            }
            if (queueTime != null) {
                if (lastDateTime == null || queueTime.isAfter(lastDateTime)) {
                    lastDateTime = queueTime;
                }
            }
            return lastDateTime;
        }
    }
}
